package dk.eclipse.android.badassapp.distance;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import dk.eclipse.android.badassapp.R;
import dk.eclipse.android.badassapp.distance.HttpGeoCoder.MyAddress;

/**
 * Given an internal person URI this activity tries to geocode the address.
 * If multiple addressses are available, the user gets to select.
 * Can be called without UI to return the list of possible addresses.
 *         
 * @author jaw 
 */
public class GeocodedAddressChoiceList extends ListActivity implements
		OnItemClickListener {
	public static final String SELECT = "dk.eclipse.android.badassapp.tab.GeocodedAddressChoiceList.SELECT";

	// Starting my constants at 1000 to avoid interference with Android systems
	// RESULT_CANCELLED. See Activity.class
	public static final int RESULT_OK = 1000;
	public static final int RESULT_BAD_PARAMETERS = 1001;
	public static final int RESULT_NO_GEOCODE = 1002;
	private Uri personUri = null;
	private List<MyAddress> addresss;

	/**
	 * 
	 * @author jaw
	 *
	 */
	private class GeoCodeAddressesTask extends
			AsyncTask<String, String, Integer> {
		private ProgressDialog dialog;
		private List<String> addressesArray;

		@Override
		protected void onPreExecute() {
			super.onPreExecute();

			dialog = ProgressDialog.show(GeocodedAddressChoiceList.this, "",
					"Loading. Please wait...", true);
		}

		@Override
		protected Integer doInBackground(String... params) {
				String contactId = personUri.getLastPathSegment();
				String address = getAddress(Long.valueOf(contactId));
				HttpGeoCoder gc = new HttpGeoCoder();
				try {
					addresss = gc.geoCode(URLEncoder.encode(address));
					addressesArray = new ArrayList<String>(addresss.size());
					for (MyAddress a : addresss) {
						addressesArray.add(a.getFormattedAddress());
					}
				} catch (IOException e) {
					e.printStackTrace();
				} catch (SAXException e) {
					e.printStackTrace();
				} catch (ParserConfigurationException e) {
					e.printStackTrace();
				}
			return addressesArray.size();
		}

		@Override
		protected void onPostExecute(Integer result) {
			super.onPostExecute(result);
			dialog.dismiss();

			switch (result) {
			case 0:
				setResult(RESULT_NO_GEOCODE);
				finish();
				break;
			case 1:
				sendPositionToCaller(0);
				break;
			default:
				setListAdapter(new ArrayAdapter<String>(GeocodedAddressChoiceList.this,
						R.layout.geocoded_address_selection, addressesArray));
			}

		}

	}

	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		// TODO Set up progress screen
		requestWindowFeature(Window.FEATURE_LEFT_ICON);
		setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.ic_app);

		ListView lv = getListView();
		lv.setTextFilterEnabled(true);
		lv.setOnItemClickListener(this);

		personUri = this.getIntent().getData();
		if (null == personUri) {
			setResult(RESULT_BAD_PARAMETERS);
			finish();
		}

		// This make take a while:
		GeoCodeAddressesTask task = new GeoCodeAddressesTask();
		task.execute("hello");
	}

	@Override
	public void onBackPressed() {
		setResult(RESULT_CANCELED);
		finish();
	}

	/**
	 * Got this from
	 * http://www.higherpass.com/Android/Tutorials/Working-With-Android
	 * -Contacts/
	 * 
	 * @param id
	 * @return
	 */
	public String getAddress(Long id) {
		String addrWhere = ContactsContract.Data.CONTACT_ID + " = ? AND "
				+ ContactsContract.Data.MIMETYPE + " = ?";
		String[] addrWhereParams = new String[] {
				String.valueOf(id),
				ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE };
		ContentResolver cr = this.getContentResolver();
		Cursor addrCur = cr.query(ContactsContract.Data.CONTENT_URI, null,
				addrWhere, addrWhereParams, null);

		StringBuffer sb = new StringBuffer();
		while (addrCur.moveToNext()) {
			appendClean(
					sb,
					addrCur
							.getString(addrCur
									.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX)));
			appendClean(
					sb,
					addrCur
							.getString(addrCur
									.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)));
			appendClean(
					sb,
					addrCur
							.getString(addrCur
									.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)));
			appendClean(
					sb,
					addrCur
							.getString(addrCur
									.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)));
			appendClean(
					sb,
					addrCur
							.getString(addrCur
									.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)));
			appendClean(
					sb,
					addrCur
							.getString(addrCur
									.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)));
			// This is a number that I think will only confuse the geocoder
			// sb.append(addrCur.getString(
			// addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)))};
		}
		if (addrCur != null) {
			addrCur.close();
		}

		return sb.toString();
	}

	private void appendClean(StringBuffer sb, String appendMe) {
		if (null != appendMe && !"".equals(appendMe)) {
			sb.append(appendMe + ", ");
		}
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) {
		sendPositionToCaller(position);
	}

	/**
	 * Send back the lat, long to caller. This is either called as callback from
	 * list selection or directly if there is only one result.
	 * 
	 * @param position
	 */
	private void sendPositionToCaller(int position) {
		Bundle b = new Bundle();
		b.putString("latitude", addresss.get(position).getLatitude());
		b.putString("longitude", addresss.get(position).getLongitude());
		Intent intent = new Intent(SELECT, personUri);
		intent.putExtras(b);
		setResult(RESULT_OK, intent);
		finish();
	}

}
